package com.javasm.sys.controller;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import com.javasm.commons.entity.AxiosResult;
import com.javasm.commons.enums.E;
import com.javasm.commons.exceptions.MvcException;
import com.javasm.commons.util.Constants;
import com.javasm.commons.util.ServletUtils;
import com.javasm.security.TokenService;
import com.javasm.service.RedisService;
import com.javasm.sys.LogMsgUtil;
import com.javasm.sys.LoginUser;
import com.javasm.sys.SysUser;
import com.javasm.sys.annotations.PassToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping
public class LoginController {
    @Autowired
    private TokenService tokenService;
    @Autowired
    private RedisService redisUtil;

    @Autowired
    private AuthenticationManager authenticationManager;


    //生成图片验证码
    @GetMapping("verifyCode")
    public AxiosResult getCode() throws IOException {
        Properties properties = new Properties();
        properties.setProperty("kaptcha.image.width", "150");
        properties.setProperty("kaptcha.image.height", "50");
        properties.setProperty("kaptcha.textproducer.char.string", "0123456789");
        properties.setProperty("kaptcha.textproducer.char.length", "4");
        Config config = new Config(properties);
        DefaultKaptcha kaptcha = new DefaultKaptcha();
        kaptcha.setConfig(config);

        String code = kaptcha.createText();
        BufferedImage image = kaptcha.createImage(code);
        System.out.println("验证码:" + code);
        //1.redis中缓存5分钟验证码
        String uuid = IdUtil.fastSimpleUUID();
        String key = Constants.CODE_KEY + uuid;
        redisUtil.set(key, code, Constants.CODE_EXPIRE_TIME, TimeUnit.MINUTES);

        //2.图片返回客户端
        FastByteArrayOutputStream out = new FastByteArrayOutputStream();
        ImageIO.write(image, "jpg", out);//把图片写到out输出流
        String str = Base64.getEncoder().encodeToString(out.toByteArray());//图片转base64编码后的字符串
        //3.uuid验证码缓存标识与图片base64字符串，返回客户端
        Map<String, String> map = new HashMap<>();
        map.put("uuid", uuid);
        map.put("img", str);
        return AxiosResult.suc(map);
    }

    @PostMapping("doLogin")
    @PassToken
    public AxiosResult login(@RequestBody SysUser user, HttpServletRequest request) {
        if (!request.getMethod().equals("POST"))
            throw new AuthenticationServiceException("只支持post方式登录:" + request.getMethod());
        if(!request.getContentType().startsWith(MediaType.APPLICATION_JSON_VALUE))
            throw new AuthenticationServiceException("只支持json格式参数:"+ request.getContentType());

        //比较用户输入的验证码与redis中缓存的验证码是否一致
        String code = user.getCode();
        String uuid = user.getUuid();
        String codeKey = Constants.CODE_KEY + uuid;
        String cacheCode= (String)redisUtil.get(codeKey);
        redisUtil.del(codeKey);
        if(StrUtil.isEmpty(cacheCode)||!cacheCode.equals(code))throw new MvcException(E.CODE_ERROR);

        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserAccount(),user.getUserPassword());
        Authentication authenticate =null;
        try{
             authenticate = authenticationManager.authenticate(authenticationToken);
        }catch (Exception e){
            throw new MvcException(E.LOGIN_ERROR);
        }

        //UserDetailsServie
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        SysUser u = loginUser.getUser();

        //生成token，并缓存reids，指定有效期
        String token = tokenService.createToken(loginUser);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("token", token);
        u.setUserPassword("");
        jsonObject.put("user", loginUser);

        // 记录登录行为
        LogMsgUtil.recordLogin(loginUser, E.LOGIN_SUCCESS.getMsg());
        return AxiosResult.suc(jsonObject);
    }

    @GetMapping("mylogout")
    public AxiosResult logout() {
        //退出操作，做如下操作：
        HttpServletRequest req = ServletUtils.getRequest();
        LoginUser loginUser = tokenService.getLoginUser(req);
        if(loginUser!=null)
            tokenService.delLoginUser(loginUser.getUuid());

        return AxiosResult.suc("退出成功");
    }
}

